#pragma once

#include <vector>
#include <string>
#include <algorithm>
#include <memory>
#include <unordered_map>
#include <mutex>
#include <sstream>
#include <iomanip>

#include "EventLoopThreadPool.h"
#include "EventLoopThread.h"

class EventLoop;

struct Node 
{
public:
  Node(const std::string& key, const uint32_t h)
    : m_key(key)
    , m_hash(h)
  {}

  Node(const Node& node) 
    : m_key(node.m_key)
    , m_hash(node.m_hash)
  {}
  Node(Node&& node)
    : m_key(std::move(node.m_key))
    , m_hash(node.m_hash)
  {}
  ~Node() = default;
  Node& operator=(const Node& node) {
    m_key = node.m_key;
    m_hash = node.m_hash;
    return *this;
  }
  bool operator< (const Node& other) const {
    return m_hash < other.m_hash;
  }
public:
  std::string m_key;
  uint32_t m_hash;
};

class ConsistentHashRing : noncopyable
{
public:
  ConsistentHashRing(const std::vector<std::string>& nodes, int numReplicas = 100);
  ~ConsistentHashRing() = default;
  void addNode(const std::string& node);
  void removeNode(const std::string& node);
  std::string getNode(const std::string& key);
private:
  std::vector<Node> m_ring;
  int m_replicas;
  // 简单 hash 函数
  uint32_t hashFunction(const std::string& key) {
    uint32_t hash = 5381;
    for (char c : key) {
      hash = ((hash << 5) + hash) + c;
    }
    return hash;
  }
};

class ConsistentHashEventLoopThreadPool : public EventLoopThreadPool
{
public:
  ConsistentHashEventLoopThreadPool(EventLoop *base, int numThreads, const std::string& name);
  ~ConsistentHashEventLoopThreadPool() = default;
  EventLoop* getNextLoop(const std::string& key) override;
  EventLoop* getNextLoop() override;
  void setThreadNum(int numThreads) override; 
private:
  std::string genHashCode(const std::string& value)
  {
    const std::size_t FNV_OFFSET_BASIS = 14695981039346656037ull;
    const std::size_t FNV_PRIME = 1099511628211ull;

    std::size_t hash = FNV_OFFSET_BASIS;
    for (char c : value) {
        hash = (hash * FNV_PRIME) ^ static_cast<std::size_t>(c);
    }
    auto toHexString = [](std::size_t hash) -> std::string {
        std::stringstream ss;
        ss << std::hex << std::setw(16) << std::setfill('0') << hash;
        return ss.str();
    };

    return toHexString(hash);
  }
private:
  std::unique_ptr<ConsistentHashRing> m_hashRing;
  std::unordered_map<std::string, EventLoop*> m_nodeMap;
  std::mutex m_mutex;
};